iT邦幫忙

2022 iThome 鐵人賽

DAY 16
0
Modern Web

React 新手村 - 填坑記系列 第 16

React 新手村 - 填坑記 - Day16 生命週期知識(二)

  • 分享至 

  • xImage
  •  

前言

昨天講到生命週期裡面的Mounting Lifecycle Methods/images/emoticon/emoticon08.gif
而今天則持續記錄下去Updating Lifecycle Methods。/images/emoticon/emoticon18.gif

Updating Lifecycle Methods

1. componentWillReceiveProps(nextProps)

每次元件接收到 props 更新時被執行,通常我們會在 componentWillReceiveProps() 傳進nextProps這參數來表示即將更新的props值,在運用this.props和nextProps來比對props前後的變化,來更新元件對應的state。

但有時候不是props有更新才會呼叫,當父元件刷新子元件時也會執行componentWillReceiveProps(),因此造成可能會被執行好幾次,所以必須得避免有任何 side effect 的 code 寫在裡面。

元件第一次 render() 時,React 不會 call componentWillReceiveProps()。

由於 componentWillReceiveProps 容易被誤解誤用,從 React 17 開始被拿掉。因此要 props 變化更新 state 請改用 getDerivedStateFromProps;如果是要聽props變化來做一些side effect操作請改用 componentDidUpdate。

2. shouldComponentUpdate(nextProps, nextState)

大多在想'最佳化效能(performance)'時使用,每當props 或 state 有更新React會在call render()重繪畫面前,先行呼叫shouldComponentUpdate()來決定是否真的需要進行render()。
雖然React會自動偵測props 和 state的改變來自動更新元件(re-render),但有些狀況就可以使用此方法來幫助React更精準判斷元件是否真的需要更新。作法很簡單可以針對新舊props和state來判斷,當執行後必須返回一個布林值(Boolean)來告訴React是否更新元件,返回false時,'componentWillUpdate()', 'render()', 'componentDidUpdate()'這些 'Lifecycole Methods' 就不會被執行。

範例如下:

    shouldComponentUpdate(nextProps, nextState) {
        console.log('nextState: ', nextState);
        if (nextState.counter > 3) return false; // => 超過 3 就不要 call render()
        return true;
    }

若沒有呼叫則預設值就會返回true

3. componentWillUpdate(nextProps, nextState)

在 shouldComponentUpdate 和 render 之間被呼叫到。適合用在和 React 無關的設定,像是檢查 window 的尺寸。因為他可能在整個運作過程中會被執行好幾次,所以一定得'避免有任何side effect的code'在裡面,同時在'componentWillUpdate()'中也禁止任何更新到元件的動作,像是call this.setState(),如果有需要更新State 請用 'getDerivedStateFromProps'。

由於 componentWillUpdate 容易被誤解誤用,從 React 17 開始被拿掉。

4. static getDerivedStateFromProps(props, state)

getDerivedStateFromProps() 是一個 static method,會在「每一次」跑 render() 之前被呼叫執行。執行時會傳入當前的 props 和 state,執行後需要返回一個物件 (object) 來表示欲更新的 state 或返回 null 表示不更新。

此方法只是為了一些少數狀況而存在,基本上都有很多其他替代方案,因此不建議使用

5. render()

是React Component一定要實作的方法,每次props或state被改變時,都會被執行一次。在render()中我們會依據當前this.props及this.state資料狀態,來決定元件當前的UI結構與顯示內容。但實作上通常會保持render()是一個pure function,不會更改State值,也不在裡面寫任何造成side-effects的code
render() 可以返回下面這幾種資料型態其一:
    *     React elements通常 render() 返回的就是用 JSX 建立的 React 元素。
    *     String / numbers可以返回字串或是數字,這會被當作是 HTML DOM 的 text nodes 來顯示。
    *     null返回 null 告訴 React 不顯示任何東西。
    *     Booleans返回布林值 false 也是告訴 React 不顯示任何東西

6. getSnapshotBeforeUpdate(prevProps, prevState)

在畫面實際渲染 (rendered) 前一刻被呼叫執行,簡單的說觸發的時機點是在 React 進行修改前,通常是更新 DOM 前。當被執行後 return 的值會被傳進 componentDidUpdate 的第三個參數。
class ScrollingList extends React.Component {

    getSnapshotBeforeUpdate(prevProps, prevState) {
        // 如果 list 內容有變動,有新東西加到 list 前面時
        if (prevProps.list.length < this.props.list.length) {
          const list = this.listRef.current;
          // 紀錄更新前一刻,捲軸的位置 scroll position
          return list.scrollHeight - list.scrollTop;
        }
        return null;
    }
}

getSnapshotBeforeUpdate 是從 React 16.3 提供的新方法。

7. componentDidUpdate(prevProps, prevState, snapshot)

會在元件更新完成、執行完 render() 重繪後被執行。而每一次元件更新時,React 確保 componentDidUpdate() 只會被執行一次。而這邊可以執行比對 prevProps/prevState 及 this.props/this.state 狀態差異,做像是存取 DOM、重畫 Canvas、重整頁面 layout、AJAX 網路呼叫等動作。如果 component 有實作 'getSnapshotBeforeUpdate' 方法那'getSnapshotBeforeUpdate'它的返回值 (return value) 會被傳進去,而'componentDidUpdate'當作第三個參數'snapshot',沒實作的話這參數值就會是 undefined。
componentDidUpdate(prevProps, prevState, snapshot) {
    // 如果有 snapshot
    if (snapshot !== null) {
      const list = this.listRef.current;
      // 調整 scroll 的位置,避免畫面才不會被新的東西推開
      list.scrollTop = list.scrollHeight - snapshot;
    }
}

元件第一次 render() 時,React 不會 call componentDidUpdate()。


上一篇
React 新手村 - 填坑記 - Day15 生命週期知識(一)
下一篇
React 新手村 - 填坑記 - Day17 生命週期知識(三)
系列文
React 新手村 - 填坑記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言